package cn.stimd.spring.context.annotation;

import cn.stimd.spring.beans.factory.annotation.AnnotatedBeanDefinition;
import cn.stimd.spring.beans.factory.config.BeanDefinition;
import cn.stimd.spring.beans.factory.config.BeanDefinitionHolder;
import cn.stimd.spring.beans.factory.support.BeanDefinitionRegistry;
import cn.stimd.spring.context.ApplicationContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;

import java.util.HashSet;
import java.util.Set;

/**
 * Created by Stimd
 * 项目地址：https://gitee.com/stimd/spring-wheel
 * 公众号：Java编程探微
 */
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
    private final Log logger = LogFactory.getLog(getClass());
    private final BeanDefinitionRegistry registry;
    private AnnotationBeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();


    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, Environment environment) {
        this.registry = registry;
        registerDefaultFilters();       //注册默认的TypeFilter，允许加载@Component声明的类
        setResourceLoader((registry instanceof ResourceLoader ? (ResourceLoader) registry : null));
        setEnvironment(environment);
    }


    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
        this(registry, registry instanceof ApplicationContext ? ((ApplicationContext) registry).getEnvironment() : null);
    }


    public void scan(String... basePackages){
        doScan(basePackages);

        //注册基于注解配置的BeanPostProcessor，比如依赖注入（@Autowired）、配置类（@Configuration）等
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }


    protected Set<BeanDefinitionHolder> doScan(String[] basePackages) {
        Set<BeanDefinitionHolder> beanDefinitions = new HashSet<>();
        for(String basePackage : basePackages){

            //1. 扫描指定目录，加载class文件，具体逻辑由父类完成
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
            for (BeanDefinition candidate : candidates) {

                //2. 解析@Lazy、@Primary、@DependsOn、@Role、@Description等注解，为BeanDefinition添加相应属性
                String beanName = this.beanNameGenerator.generateBeanName(candidate);       //生成Bean的名称
                if (candidate instanceof AnnotatedBeanDefinition) {
                    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
                }

                //3. 检查是否与已存在的Bean冲突，如果没有则将BeanDefinition添加到容器中
                if(!this.registry.containsBeanDefinition(beanName)){
                    logger.info("[Context] [扫描组件] --> beanName: " + beanName);
                    registry.registerBeanDefinition(beanName, candidate);
                    BeanDefinitionHolder holder = new BeanDefinitionHolder(candidate, beanName);
                    beanDefinitions.add(holder);
                }
            }
        }
        return beanDefinitions;
    }


    @Override
    protected BeanDefinitionRegistry getRegistry() {
        return this.registry;
    }
}
